﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace DigitalQuran.Statistic
{
    /// <summary>
    /// Represents Letter Statistics Table
    /// </summary>
    public sealed class LetterStatisticTable : List<LetterStatistic>, IComparer<LetterStatistic>
    {
        public LetterStatisticTable() {
            Text = string.Empty;
        }

        /// <summary>
        /// Add new letter statistic of updates existing if letter already exist
        /// </summary>
        /// <param name="letter">Letter whose statistic is to update or add</param>
        public void AddOrUpdate(char letter)
        {            
            for (int j = 0; j < this.Count; j++)
            {
                if (letter == this[j].Letter)
                {
                    base[j].Frequency++;
                    return;
                }
            }

            this.Add(new LetterStatistic { Letter = letter, Order = this.Count + 1 });
        }

        /// <summary>
        /// Gets the text whose statistic this table holds
        /// </summary>
        public string Text { get; internal set; }

        /// <summary>
        /// Gets the total frequency count
        /// </summary>
        public int FrequencyCount { get; internal set; }

        /// <summary>
        /// Sorts the table according to the sorting method
        /// </summary>
        /// <param name="method">Sorting method</param>
        public void Sort(SortMethod method, SortOrder sortOrder)
        {
            SortMethod = method;
            SortOrder = sortOrder;
            this.Sort(this);
        }

        SortMethod SortMethod = SortMethod.ByOrder;
        SortOrder SortOrder = SortOrder.Ascending;

        /// <summary>
        /// Compares two letter statistics
        /// </summary>
        /// <param name="x">Letter Statistics to compare with</param>
        /// <param name="y">Letter statistics to compare</param>
        /// <returns>Return the difference between letter statistics</returns>
        public int Compare(LetterStatistic x, LetterStatistic y)
        {
            if (SortOrder == SortOrder.Ascending)
            {
                if (SortMethod == SortMethod.ByOrder)
                    return x.Order.CompareTo(y.Order);
                else if (SortMethod == SortMethod.ByLetter)
                    return x.Letter.CompareTo(y.Letter);
                else if (SortMethod == SortMethod.ByFrequency)
                {
                    if (x.Frequency.CompareTo(y.Frequency) == 0)
                        return x.Order.CompareTo(y.Order);
                    return x.Frequency.CompareTo(y.Frequency);
                }
                else
                    return x.Frequency.CompareTo(y.Frequency);
            }
            else
            {
                if (SortMethod == SortMethod.ByOrder)
                    return y.Order.CompareTo(x.Order);
                else if (SortMethod == SortMethod.ByLetter)
                    return y.Letter.CompareTo(x.Letter);
                else if (SortMethod == SortMethod.ByFrequency)
                {
                    if (y.Frequency.CompareTo(x.Frequency) == 0)
                        return y.Order.CompareTo(x.Order);
                    return y.Frequency.CompareTo(x.Frequency);
                }
                else
                    return y.Frequency.CompareTo(x.Frequency);
            }
        }

        /// <summary>
        /// Save the Current Table as binary file
        /// </summary>
        /// <param name="path">path where to save</param>
        public void SaveAsBinary(string path)
        {            
            using (var stream = new FileStream(path, FileMode.Create))
            using (var writer = new BinaryWriter(stream))
            {
                /* Binary File Content will be maintained as
                 * - Text (String)
                 * 
                 * (LOOP)
                 *      - Order (Int32)
                 *      - Letter (Char)
                 *      - Frequency (Int32)
                 */
                writer.Write(Text);
                foreach (var s in this)
                {
                    writer.Write(s.Order);
                    writer.Write(s.Letter);
                    writer.Write(s.Frequency);
                }
            }
        }

        /// <summary>
        /// Save the Current Table as Plain Text File
        /// </summary>
        /// <param name="path">path where to save</param>
        public void SaveAsText(string path)
        {
            using (var writer = new StreamWriter(path, false, Encoding.Unicode))
            {
                writer.WriteLine("+{0}+ LETTER STATISTICS +{0}+", new string('=', 12));
                writer.WriteLine();

                writer.WriteLine("Text: {0}", Text);
                writer.WriteLine();

                writer.WriteLine("{0}", new string('-', 25));
                writer.WriteLine("Order\tLetter\tFrequency");
                writer.WriteLine("{0}", new string('-', 25));

                foreach (var s in this)
                {
                    writer.WriteLine("{0}\t{1}\t{2}", s.Order, s.Letter, s.Frequency);
                }
            }
        }

        /// <summary>
        /// Save the Current Table as CSV File
        /// </summary>
        /// <param name="path">path where to save</param>
        public void SaveAsCsv(string path)
        {
            using (var writer = new StreamWriter(path, false, Encoding.UTF8))
            {
                writer.WriteLine("Order,Letter,Frequency");

                foreach (var s in this)
                {
                    writer.WriteLine("{0},{1},{2}", s.Order, s.Letter, s.Frequency);
                }

                writer.WriteLine("Total,,{0}", FrequencyCount);
            }
        }

        public new void Clear()
        {
            base.Clear();
            FrequencyCount = 0;
            Text = null;
        }
    }
}